#include "engine.h"
#include "texturesdl.h"
#include "sdl_opengl.h"

using std::string;
using namespace EPOC;

/** Default constructor. **/
Engine::Engine()
{
	SetClassID(kCLASSID_ENGINE);

	m_pScreen = NULL;
	m_sTitle = "";
 
	m_lLastTick = 0;
	m_nFPSTickCounter = 0;
	m_nFPSCounter = 0;
	m_nCurrentFPS = 50;
	//m_nBpp = 0;

	m_fTimeDelta = 0.0f;
 
	m_bMinimized = false;
	m_bFullScreen = false;
	m_bAudioSupport = true;

	m_nWidth = 0;
	m_nHeight = 0;
	//m_nFlags = 0;
	/*m_nRenderMode = kRENDER_MODE_UNKNOWN;
	m_pVideoInfo = NULL;*/

	SetFPSCapEnabled(false);
	SetFPSCap(60);

	m_nQuitKey = SDLK_ESCAPE;
}
 
/** Destructor. **/
Engine::~Engine()
{
	Engine::Cleanup();
}

void Engine::Cleanup()
{
	if(m_pScreen)
	{
		m_pScreen->Release();
		m_pScreen = NULL;
	}

	TTF_Quit();
	SDL_Quit();
}

void Engine::Start(string sTitle, int nWidth, int nHeight, bool bFullScreen)
{
	Start(sTitle, nWidth, nHeight, -1, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

	_asm int 3;
}


//Initialize SDL, the window and the additional data
void Engine::Start(string sTitle, int nWidth, int nHeight, int nDeviceIndex, Uint32 nSdlWindowFlags, Uint32 nSdlRendererFlags)
{

	printf( "Engine: Starting up the engine!\n");

	// register SDL_Quit to be called at exit; makes sure things are cleaned up when we quit.
	atexit(SDL_Quit );

	// initialize SDL's subsystems
	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) 
	{
		fprintf( stderr, "Engine: Error, unable to initialize SDL: %s\n", SDL_GetError() );
		exit( 1 );
	}

	if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
	{
		fprintf( stderr, "Engine: Error, unable to initialize SDL subsystem AUDIO: %s\n", SDL_GetError() );
		fprintf( stderr, "Engine: Error, audio disabled\n");
		//exit( 1 );
		m_bAudioSupport = false;
	}

	printf( "Engine: SDL was successfully initialized\n");



	if(nSdlWindowFlags & SDL_WINDOW_OPENGL)
	{
		/*	
		SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );		
		SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );	
		SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
		SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
		*/

		SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
	}

	// Attempt to create a window with the specified height and width.
	if(CreateWindowAndRenderer(sTitle, nWidth, nHeight, nDeviceIndex, nSdlWindowFlags, nSdlRendererFlags) == false)
	{
		fprintf( stderr, "Engine: Error, unable to setup video mode (%s)\n", SDL_GetError() );
		exit( 1 );
	}

	SDL_RendererInfo displayRenderInfo;
	SDL_GetRendererInfo(m_pRenderer, &displayRenderInfo);



	
	if(TTF_Init()==-1)
	{
		printf("Engine: Error, unable to initialize TTF (%s)\n", TTF_GetError());
		exit(1);
	}

#ifdef _DEBUG
	SetTitle(DEFAULT_TITLE + sTitle);
#else
	SetTitle(sTitle);
#endif

	if(Initialize() == false)
	{
		fprintf( stderr, "Engine: Error, failed to initialize engine\n");
		exit(1);
	}

	m_lLastTick = SDL_GetTicks();
	m_bQuit = false;
 
	// Main loop: loop forever.
	while(!m_bQuit)
	{
		// Handle events
		DoEvents();

		if(DoUpdate() == false)
			m_bQuit = true;
 
		// render stuff
		DoRender();
	}
}
 
/** Handles all controller inputs.
	@remark This function is called once per frame.
**/
void Engine::DoEvents()
{
	// Poll for events, and handle the ones we care about.
	SDL_Event event;
	while(SDL_PollEvent(&event)) 
	{
		// Handle events in children
		HandleEvent(&event);

		switch(event.type ) 
		{
		case SDL_KEYDOWN:
			{
				// If escape is pressed set the Quit-flag
				if (event.key.keysym.sym == m_nQuitKey)
				{
					m_bQuit = true;
					break;
				}
			}
			break;
 
			case SDL_QUIT:
			{
				m_bQuit = true;
			}
			break;

			case SDL_WINDOWEVENT_RESIZED: // It's a RESIZE Event?
			{

			}
			break;

 
			case SDL_WINDOWEVENT_FOCUS_GAINED: // WINDOW GOT FOCUS, WHAT HAPPENED? TODO: Check what happened
			{
				/*
				if ( event.state & SDL_APPACTIVE ) 
				{
					if(event.active.gain ) 
					{
						if(m_bMinimized)
						{
							m_bMinimized = false;
							NotifyWindowActive();
						}
					}
					else
					{
						if(m_bMinimized == false)
						{
							m_bMinimized = true;
							NotifyWindowInactive();
						}
					}

					if(event.active.state & SDL_APPMOUSEFOCUS)					// The Mouse Cursor Has Left/Entered The Window Space?
					{
						if(event.active.gain)									// Entered?
							m_bMouseFocus = true;								// Report It Setting AppStatus.MouseFocus
						else													// Otherwhise
							m_bMouseFocus = false;								// The Cursor Has Left, Reset AppStatus.MouseFocus
					}

					if(event.active.state & SDL_APPINPUTFOCUS)					// The Window Has Gained/Lost Input Focus?
					{
						if(event.active.gain)									// Gained?
							m_bKeyboardFocus = true;							// Report It Where You Know (You Always Report, You're A Spy, Aren't You?!)
						else													// Otherwhise
							m_bKeyboardFocus = false;							// Reset AppStatus.KeyboardFocus
					}
				}
				*/
			}
			break;

		} // switch
	} // while (handling input)
}
 
/** Handles the updating routine. **/
bool Engine::DoUpdate() 
{
	//TODO: Create a framerate cap
	
	if( IsFPSCapEnabled() )
	{
		if( (SDL_GetTicks() - m_lLastTick) < (1000 / GetFPSCap() ) ) 
			SDL_Delay( (1000 / GetFPSCap()) - (SDL_GetTicks() - m_lLastTick) ); 
	}

	long iElapsedTicks = SDL_GetTicks() - m_lLastTick;
	m_lLastTick = SDL_GetTicks();

	m_fTimeDelta = (float)(iElapsedTicks);
	if(Update(m_fTimeDelta) == false)
		return false;
 
	m_nFPSTickCounter += iElapsedTicks;

	return true;
}
 
/** Handles the rendering and FPS calculations. **/
void Engine::DoRender()
{
	++m_nFPSCounter;
	if(m_nFPSTickCounter >= 1000 )
	{
		m_nCurrentFPS = m_nFPSCounter;
		m_nFPSCounter = 0;
		m_nFPSTickCounter = 0;
	}
	
	//if(m_pScreen) 
		Render( m_pRenderer);	
}
 
bool Engine::CreateWindowAndRenderer(string sTitle, int nWidth, int nHeight, int nDeviceIndex, Uint32 nWindowFlags, Uint32 nRendererFlags)
{
	m_sTitle = sTitle;
	m_nWidth  = nWidth;
	m_nHeight = nHeight;
	m_bFullScreen = !(nWindowFlags & SDL_WINDOW_FULLSCREEN);
	
	//if(m_bFullScreen)
	//	nWindowFlags |= SDL_WINDOW_FULLSCREEN;

	m_pWindow = SDL_CreateWindow(sTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_nWidth, m_nHeight, nWindowFlags);
	if(!m_pWindow)
	{
		fprintf( stderr, "Engine: Error, unable to create SDL WINDOW (%s)\n", SDL_GetError() );
		return false;
	}
	else // if window was successfully created, then create the renderer
	{	
		m_pRenderer = SDL_CreateRenderer(m_pWindow, nDeviceIndex, nRendererFlags);
		if(!m_pRenderer)
		{
			fprintf( stderr, "Engine: Error, unable to create SDL RENDERER (%s)\n", SDL_GetError() );
			return false;
		}
	}

	return true;
}

void Engine::SetTitle(string sTitle)
{
	m_sTitle = sTitle;

	if(m_pWindow != NULL)
		SDL_SetWindowTitle(m_pWindow, m_sTitle.c_str());
}